package com.xiaoshuidi.cloud.module.rooms.repository.elsticsearch;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.framework.common.util.json.JsonUtils;
import com.xiaoshuidi.cloud.module.rooms.api.roomstate.dto.RoomContractInfoDTO;
import com.xiaoshuidi.cloud.module.rooms.controller.admin.roomel.vo.UpdateRoomelEntiry;
import com.xiaoshuidi.cloud.module.rooms.controller.app.home.vo.OtherRoomsInTheSameListingRespVO;
import com.xiaoshuidi.cloud.module.rooms.controller.app.home.vo.SameResidentialListingsRespVO;
import com.xiaoshuidi.cloud.module.rooms.controller.app.map.vo.GetMapRespVO;
import com.xiaoshuidi.cloud.module.rooms.controller.app.map.vo.MapFindSearchRespVO;
import com.xiaoshuidi.cloud.module.rooms.convert.roomel.MyRoomelConvert;
import com.xiaoshuidi.cloud.module.rooms.enums.ApiConstants;
import com.xiaoshuidi.cloud.module.rooms.enums.RentStatusEnum;
import com.xiaoshuidi.cloud.module.rooms.enums.RoomTypeEnum;
import com.xiaoshuidi.cloud.module.rooms.pojo.RoomHouse;
import com.xiaoshuidi.cloud.module.rooms.pojo.roomel.RoomelEntity;
import com.xiaoshuidi.cloud.module.rooms.repository.RoomHouseRepository;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.PipelineAggregatorBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.*;
import org.elasticsearch.search.aggregations.pipeline.BucketSortPipelineAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Repository;
import org.zxp.esclientrhl.repository.ElasticsearchTemplate;


import java.io.IOException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.xiaoshuidi.cloud.module.rooms.pojo.roomel.RoomelEntityMapping.*;

@Slf4j
@Repository
@RequiredArgsConstructor
public class RoomelEntityRepository {
    private static final String index = "fy_roomel";

    private final ElasticsearchTemplate elasticsearchTemplate;
    private final RoomHouseRepository roomHouseRepository;
    private final RestHighLevelClient restHighLevelClient;

    /**
     * 分页查询房源所属小区下的其他房源
     *
     * @param roomAreaId         小区ID
     * @param excludeRoomHouseId 该房源ID
     * @param isWhole            是否整租
     * @param pageNo             分页参数
     * @param pageSize           分页参数
     * @param tenantId
     */
    public CommonResult<PageResult<SameResidentialListingsRespVO>> getRoomHouseByAreaIdAndExclude(@NonNull Long roomAreaId, @NonNull Long excludeRoomHouseId, @NonNull Boolean isWhole, @NonNull Integer pageNo, @NonNull Integer pageSize, Long tenantId) {
        // 查询请求
        SearchRequest searchRequest = new SearchRequest(index);
        // 查询条件
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery(TenantId, tenantId))
                .must(QueryBuilders.termQuery(IsStop, false))
                .must(QueryBuilders.termQuery(RoomAreaId, roomAreaId))
                .must(QueryBuilders.termQuery(HouseState, RentStatusEnum.EMPTY.getValue()))
                .mustNot(QueryBuilders.termQuery(Id, excludeRoomHouseId));


        // 查询整租 or 合租的子房间
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.should(QueryBuilders.termQuery(IsWhole, true));
        BoolQueryBuilder boolQueryBuilder2 = new BoolQueryBuilder();

        BoolQueryBuilder boolQueryBuilder3 = new BoolQueryBuilder();
        boolQueryBuilder3.must(QueryBuilders.termQuery(IsWhole, false));
        boolQueryBuilder3.must(QueryBuilders.existsQuery(SuperId));
        boolQueryBuilder2.must(boolQueryBuilder3);

        BoolQueryBuilder boolQueryBuilder5 = new BoolQueryBuilder();
        boolQueryBuilder5.mustNot(QueryBuilders.termQuery(RoomType + ".keyword", RoomTypeEnum.GGQY.getValue()));
        boolQueryBuilder2.must(boolQueryBuilder5);
        boolQueryBuilder.should(boolQueryBuilder2);

        queryBuilder.must(boolQueryBuilder);

        // 设置查询条件，分页条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        searchSourceBuilder.from((pageNo - 1) * pageSize);
        searchSourceBuilder.size(pageSize);
        searchRequest.source(searchSourceBuilder);
        List<SameResidentialListingsRespVO> respVOS = new ArrayList<>();
        Long count = 0l;
        try {
            // ES查询
            SearchResponse search = elasticsearchTemplate.search(searchRequest);
            // 总条数
            count = search.getHits().getTotalHits().value;
            // 处理查询结果
            for (SearchHit hit : search.getHits().getHits()) {
                RoomelEntity roomelEntity = JsonUtils.parseObject(hit.getSourceAsString(), RoomelEntity.class);
                RoomHouse roomHouse = roomHouseRepository.myGetById(roomelEntity.getId());
                SameResidentialListingsRespVO respVO = new SameResidentialListingsRespVO()
                        .setRoomHouseId(roomelEntity.getId().toString())
                        .setIsWhole(roomelEntity.getIsWhole())
                        .setRoomFullName(roomelEntity.getFullName())
                        .setSpace(roomelEntity.getSpace())
                        .setIsFullRoom(false)
                        .setPrice(roomelEntity.getPrice())
                        .setRoomHouseTypeName(roomelEntity.getRoomHouseTypeName())
                        .setPicUrl(StrUtil.isNotEmpty(roomHouse.getPicUrl()) ? roomHouse.getPicUrl().split(",")[0] : "");
                // 如果是合租，判断是否已经出租
                if (!isWhole) {
                    respVO.setIsFullRoom(!RentStatusEnum.EMPTY.getValue().equals(roomelEntity.getHouseState()));
                }
                respVOS.add(respVO);
            }
        } catch (Exception e) {
            log.error("getRoomHouseByAreaIdAndExclude异常", e);
        }
        return CommonResult.success(new PageResult<>(respVOS, count));
    }

    /**
     * 社区-房源详情-同房源其他房间
     *
     * @param excludeRoomHouseId 房源ID
     * @param tenantId           租户ID
     * @param apartmentAreaId    小区id
     * @return
     */
    public CommonResult<List<OtherRoomsInTheSameListingRespVO>> otherRoomsInTheSameListing(Long excludeRoomHouseId, Long apartmentAreaId, Long tenantId) {
        // 查询请求
        SearchRequest searchRequest = new SearchRequest(index);
        // 查询条件
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery(TenantId, tenantId))
                .must(QueryBuilders.termQuery(IsStop, false))
                .must(QueryBuilders.termQuery(ApartmentAreaId, apartmentAreaId))
                // 不能是公区
                .mustNot(QueryBuilders.termQuery(RoomType + ".keyword", RoomTypeEnum.GGQY.getValue()))
                .mustNot(QueryBuilders.termQuery(Id, excludeRoomHouseId));
        // 设置查询条件，分页条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        searchRequest.source(searchSourceBuilder);
        List<OtherRoomsInTheSameListingRespVO> respVOS = new ArrayList<>();
        try {
            SearchResponse search = elasticsearchTemplate.search(searchRequest);
            for (SearchHit hit : search.getHits().getHits()) {
                RoomelEntity roomelEntity = JsonUtils.parseObject(hit.getSourceAsString(), RoomelEntity.class);
                RoomHouse roomHouse = roomHouseRepository.myGetById(roomelEntity.getId());
                OtherRoomsInTheSameListingRespVO respVO = new OtherRoomsInTheSameListingRespVO()
                        .setRoomHouseId(roomelEntity.getId().toString())
                        .setIsWhole(roomelEntity.getIsWhole())
                        .setRoomFullName(roomelEntity.getFullName())
                        .setSpace(roomelEntity.getSpace())
                        .setIsFullRoom(false)
                        .setPrice(roomelEntity.getPrice())
                        .setRoomHouseTypeName(roomelEntity.getRoomHouseTypeName())
                        .setPicUrl(StrUtil.isNotEmpty(roomHouse.getPicUrl()) ? roomHouse.getPicUrl().split(",")[0] : "");
                respVOS.add(respVO);
            }
        } catch (Exception e) {
            log.error("社区-房源详情-同房源其他房间异常:{}", e);
        }
        return CommonResult.success(respVOS);
    }

    /**
     * 获取经纬度附近10公里内的前20条房源
     * @param longitude 经度
     * @param latitude 纬度
     * @param tenantId 租户ID
     * @return
     */
    public CommonResult<List<OtherRoomsInTheSameListingRespVO>> recommendListingsNearYou(String longitude, String latitude,Long excludeRoomHouseId, Long tenantId) {
        List<OtherRoomsInTheSameListingRespVO> respVOS = new ArrayList<>();
        if(!ObjectUtil.isAllNotEmpty(longitude, latitude)){
            return CommonResult.success(respVOS);
        }
        SearchRequest searchRequest = new SearchRequest(index);
        log.info("推荐附近的房源,经度:{},纬度:{}", longitude, latitude);
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                // 该租户下的
                .must(QueryBuilders.termQuery(TenantId, tenantId))
                // 空房
                .must(QueryBuilders.termQuery(HouseState, RentStatusEnum.EMPTY.getValue()))
                // 未锁定
                .must(QueryBuilders.termQuery(IsLock, false))
                // 未停用
                .must(QueryBuilders.termQuery(IsStop, false))
                // 不包含当前房源
                .mustNot(QueryBuilders.termQuery(Id, excludeRoomHouseId))
                // 附近10公里内
                .must(QueryBuilders.geoDistanceQuery(ApartmentAreaGeo).distance("10", DistanceUnit.KILOMETERS).point(Double.parseDouble(latitude), Double.parseDouble(longitude)))
                ;
        // 查询整租 or 合租的子房间
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.should(QueryBuilders.termQuery(IsWhole, true));
        BoolQueryBuilder boolQueryBuilder2 = new BoolQueryBuilder();

        BoolQueryBuilder boolQueryBuilder3 = new BoolQueryBuilder();
        boolQueryBuilder3.must(QueryBuilders.termQuery(IsWhole, false));
        boolQueryBuilder3.must(QueryBuilders.existsQuery(SuperId));
        boolQueryBuilder2.must(boolQueryBuilder3);

        BoolQueryBuilder boolQueryBuilder5 = new BoolQueryBuilder();
        boolQueryBuilder5.mustNot(QueryBuilders.termQuery(RoomType + ".keyword", RoomTypeEnum.GGQY.getValue()));
        boolQueryBuilder2.must(boolQueryBuilder5);
        boolQueryBuilder.should(boolQueryBuilder2);

        queryBuilder.must(boolQueryBuilder);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        // 距离排序，由近到远
        searchSourceBuilder.sort(SortBuilders.geoDistanceSort(ApartmentAreaGeo, Double.parseDouble(latitude), Double.parseDouble(longitude)).order(SortOrder.ASC).unit(DistanceUnit.METERS));
        // 截取前20条数据
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(20);
        searchRequest.source(searchSourceBuilder);

        try {
            SearchResponse search = elasticsearchTemplate.search(searchRequest);
            for (SearchHit hit : search.getHits().getHits()) {
                RoomelEntity roomelEntity = JsonUtils.parseObject(hit.getSourceAsString(), RoomelEntity.class);
                RoomHouse roomHouse = roomHouseRepository.myGetById(roomelEntity.getId());
                OtherRoomsInTheSameListingRespVO respVO = new OtherRoomsInTheSameListingRespVO()
                        .setRoomHouseId(roomelEntity.getId().toString())
                        .setIsWhole(roomelEntity.getIsWhole())
                        .setRoomFullName(roomelEntity.getFullName())
                        .setSpace(roomelEntity.getSpace())
                        .setIsFullRoom(false)
                        .setPrice(roomelEntity.getPrice())
                        .setRoomHouseTypeName(roomelEntity.getRoomHouseTypeName())
                        .setPicUrl(StrUtil.isNotEmpty(roomHouse.getPicUrl()) ? roomHouse.getPicUrl().split(",")[0] : "");
                respVOS.add(respVO);
            }
        } catch (Exception e) {
            log.error("推荐附近房源接口异常：{}", e);
        }
        return CommonResult.success(respVOS);
    }

    /**
     * 地图找房-搜索-根据小区名获取对应的小区信息
     *
     * @param searchBox      搜索框内容
     * @param isConcentrated 是否集中式
     * @param roomHouseState 房源状态 1：可租房源 2：全部房源
     * @param pageNo         分页参数
     * @param pageSize       分页参数
     * @param tenantId       租户id
     * @return
     */
    public CommonResult<PageResult<GetMapRespVO>> mapFindSearch(String searchBox, Boolean isConcentrated, String roomHouseState, Integer pageNo, Integer pageSize, Long tenantId) {
        SearchRequest searchRequest = new SearchRequest(index);
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery(IsStop, false))
                .must(QueryBuilders.termQuery(TenantId, tenantId));

        // 查询整租 or 合租的子房间
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.should(QueryBuilders.termQuery(IsWhole, true));
        BoolQueryBuilder boolQueryBuilder2 = new BoolQueryBuilder();

        BoolQueryBuilder boolQueryBuilder3 = new BoolQueryBuilder();
        boolQueryBuilder3.must(QueryBuilders.termQuery(IsWhole, false));
        boolQueryBuilder3.must(QueryBuilders.existsQuery(SuperId));
        boolQueryBuilder2.must(boolQueryBuilder3);

        BoolQueryBuilder boolQueryBuilder5 = new BoolQueryBuilder();
        boolQueryBuilder5.mustNot(QueryBuilders.termQuery(RoomType + ".keyword", RoomTypeEnum.GGQY.getValue()));
        boolQueryBuilder2.must(boolQueryBuilder5);
        boolQueryBuilder.should(boolQueryBuilder2);

        queryBuilder.must(boolQueryBuilder);

        if(StrUtil.isNotEmpty(searchBox)){
            queryBuilder.must(QueryBuilders.wildcardQuery(ApartmentAreaName + ".keyword", "*" + searchBox + "*"));
        }
        if(ObjectUtil.isNotEmpty(isConcentrated)){
            queryBuilder.must(QueryBuilders.termQuery(IsConcentrated, isConcentrated));
        }
        if(ObjectUtil.isNotEmpty(roomHouseState) && roomHouseState.equals("1")){
            queryBuilder.must(QueryBuilders.termQuery(HouseState, RentStatusEnum.EMPTY.getValue()));
            queryBuilder.must(QueryBuilders.termQuery(IsLock, false));
        }
        TermsAggregationBuilder areaGroup = AggregationBuilders.terms("areaGroup").field(RoomAreaId).size(pageNo * pageSize).order(BucketOrder.key(true));
        // select 的字段
        TopHitsAggregationBuilder apartmentInfoTopHits = AggregationBuilders.topHits("areaInfo")
                .fetchSource(new String[]{Id, ApartmentId, RoomAreaId, ApartmentAreaId, District, ApartmentAreaName, ApartmentAreaGeo}, null).size(1);
        // 获取分组后的桶数量
        CardinalityAggregationBuilder cardinalityAggregationBuilder = AggregationBuilders.cardinality("bucketCount").field(RoomAreaId);
        // 排序条件
        List<FieldSortBuilder> sortList = new ArrayList<>();
        // 按创建时间倒序
        MaxAggregationBuilder maxAggregationBuilder = AggregationBuilders.max("maxSort").field(CreateTime);
        areaGroup.subAggregation(maxAggregationBuilder);
        sortList.add(new FieldSortBuilder("maxSort").order(SortOrder.DESC));
        // 设置桶排序和分页
        BucketSortPipelineAggregationBuilder bucketSort = PipelineAggregatorBuilders
                .bucketSort("sort", sortList)
                .from((pageNo - 1) * pageSize)
                .size(pageSize);
        areaGroup.subAggregation(apartmentInfoTopHits);
        areaGroup.subAggregation(bucketSort);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        searchSourceBuilder.aggregation(areaGroup);
        searchSourceBuilder.aggregation(cardinalityAggregationBuilder);
        searchRequest.source(searchSourceBuilder);

        List<GetMapRespVO> respVOS = new ArrayList<>();
        long count = 0;
        try {
            SearchResponse search = elasticsearchTemplate.search(searchRequest);
            log.info("地图找房-搜索-根据小区名获取对应的小区信息ES请求语句:{}", searchRequest.source().toString());
            ParsedCardinality cardinality = (ParsedCardinality) search.getAggregations().getAsMap().get("bucketCount");
            count = cardinality.getValue();

            ParsedTerms areaGroupTerms = (ParsedTerms) search.getAggregations().getAsMap().get("areaGroup");
            areaGroupTerms.getBuckets().stream().forEach(areaGroupTerm -> {
                ParsedTopHits areaInfoTopHits = (ParsedTopHits) areaGroupTerm.getAggregations().getAsMap().get("areaInfo");
                GetMapRespVO respVO = new GetMapRespVO();
                // 查询小区内有多少套房源
                respVO.setNum(areaGroupTerm.getDocCount());
                respVO.setRoomAreaId(Long.parseLong(areaGroupTerm.getKeyAsString()));
                SearchHit[] hits = areaInfoTopHits.getHits().getHits();
                // 检查小区内是否含有集中式房源
                if(ObjectUtil.isNotEmpty(hits)){
                    respVO.setIsHasConcentrated(checkIsPresent(respVO.getRoomAreaId(), respVO));
                }
                for (SearchHit hit : hits) {
                    Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                    String apartmentAreaName = (String) sourceAsMap.get("apartmentAreaName");
                    String geo = (String)sourceAsMap.get("apartmentAreaGeo");
                    String[] geoSplit = geo.split(",");
                    if (ObjectUtil.isNotEmpty(geoSplit)) {
                        respVO.setLatLon(String.valueOf(geoSplit[1] + "," + geoSplit[0]));
                    }
                    respVO.setName(apartmentAreaName);
                    respVO.setDistrict((String) sourceAsMap.get("district"));
                }
                respVO.setLevel(3);
                respVOS.add(respVO);
            });
        } catch (Exception e) {
            log.error("地图找房-搜索异常：{}", e);
        }
        return CommonResult.success(new PageResult<>(respVOS, count));
    }

    public Boolean checkIsPresent(Long roomAreaId, GetMapRespVO respVO) {
        List<RoomHouse> roomHouses = roomHouseRepository.getByRoomAreaIdAndIsConcentrated(roomAreaId, true);
        if(ObjectUtil.isNotEmpty(roomHouses)){
            // 从业务方面, 一个小区只会对应一个门店, 因此取一个房源的门店ID作为该小区的门店ID
            respVO.setApartmentId(roomHouses.get(0).getApartmentId());
        }
        return ObjectUtil.isNotEmpty(roomHouses);
    }

    /**
     * 根据租客的手机号查询对应的房源信息
     * @param tenantId
     * @param phone
     * @return
     */
    public List<RoomelEntity> getRoomHouseByTenantPhone(Long tenantId, String phone) {
        SearchRequest searchRequest = new SearchRequest(index);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery(TenantId, tenantId))
                .must(QueryBuilders.termQuery(IsStop, false))
                .must(QueryBuilders.wildcardQuery(Tenantinfo, "*" + phone + "*"));

        searchSourceBuilder.query(queryBuilder);
        searchRequest.source(searchSourceBuilder);
        SearchResponse search = null;
        try {
            search = elasticsearchTemplate.search(searchRequest);
            long value = search.getHits().getTotalHits().value;
            searchSourceBuilder.from(0);
            searchSourceBuilder.size((int)value);
            search = elasticsearchTemplate.search(searchRequest);
            log.info("根据租客的手机号查询对应的房源信息-查询语句:{}", searchRequest.source().toString());
        } catch (Exception e) {
            log.error("根据租客的手机号查询对应的房源信息异常", e);
        }
        return Arrays.stream(search.getHits().getHits()).map(hit -> JsonUtils.parseObject(hit.getSourceAsString(), RoomelEntity.class)).collect(Collectors.toList());
    }

    /**
     * 更新es房源数据
     * @param updateRoomelEntiry
     * @return
     */
    public Boolean updateRoomelEntiry(UpdateRoomelEntiry updateRoomelEntiry){
        try {
            SearchRequest searchRequest = new SearchRequest(ApiConstants.ROOMELENTIRY);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            boolQueryBuilder.must(QueryBuilders.termQuery("id", updateRoomelEntiry.getId()));
            searchSourceBuilder.query(boolQueryBuilder);
            searchRequest.source(searchSourceBuilder);
            SearchResponse search = elasticsearchTemplate.search(searchRequest);

            BulkRequest request = new BulkRequest();

            for (SearchHit hit : search.getHits().getHits()) {
                RoomelEntity roomel = JsonUtils.parseObject(hit.getSourceAsString(), RoomelEntity.class);
                MyRoomelConvert.convert(updateRoomelEntiry, roomel);
                IndexRequest indexRequest = new IndexRequest(ApiConstants.ROOMELENTIRY).id(roomel.getId().toString())
                        .source(JsonUtils.toJsonString(roomel), XContentType.JSON);
                request.add(indexRequest);
            }
            restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("更新es房源数据异常", e);
            throw new RuntimeException(e);
        }
        return Boolean.TRUE;
    }

    /**
     * 续租合同账单支付后,更新房源的续租合同信息
     * @param roomHouseId
     * @param renewalContractId
     * @param renewalEndTime
     * @return
     */
    public CommonResult<Boolean> updateContractInfoByRenewal(Long roomHouseId, Long renewalContractId, LocalDate renewalEndTime) {
        try {
            SearchRequest searchRequest = new SearchRequest(ApiConstants.ROOMELENTIRY);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.termQuery(Id, roomHouseId));
            searchSourceBuilder.query(boolQueryBuilder);
            searchRequest.source(searchSourceBuilder);
            SearchResponse search = elasticsearchTemplate.search(searchRequest);
            BulkRequest request = new BulkRequest();
            for (SearchHit hit : search.getHits().getHits()) {
                RoomelEntity roomel = JsonUtils.parseObject(hit.getSourceAsString(), RoomelEntity.class);
                String contractInfo = roomel.getContractInfo();
                if(ObjectUtil.isNotEmpty(contractInfo)){
                    RoomContractInfoDTO roomContractInfoDTO = JsonUtils.parseObject(contractInfo, RoomContractInfoDTO.class);
                    roomContractInfoDTO.setLeaseRenewalContractId(renewalContractId);
                    roomContractInfoDTO.setLeaseRenewalExpiryDate(renewalEndTime);
                    roomel.setContractInfo(JsonUtils.toJsonString(roomContractInfoDTO));
                    IndexRequest indexRequest = new IndexRequest(ApiConstants.ROOMELENTIRY).id(roomel.getId().toString())
                            .source(JsonUtils.toJsonString(roomel), XContentType.JSON);
                    request.add(indexRequest);
                }
                restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
            }
        } catch (Exception e) {
            log.error("续租合同账单支付后,更新房源的续租合同信息异常", e);
            throw new RuntimeException(e);
        }
        return CommonResult.success(Boolean.TRUE);
    }

    /**
     * 更新房源ES中的租住人手机号
     * @param tenantId 租户id
     * @param mobile 原手机号
     * @param newMobile 新手机号
     * @return
     */
    public CommonResult<Boolean> updateRoomESRenterMobile(Long tenantId, String mobile, String newMobile) {
        try {
            List<RoomelEntity> roomHouseByTenantPhone = this.getRoomHouseByTenantPhone(tenantId, mobile);
            BulkRequest request = new BulkRequest();
            for (RoomelEntity roomel : roomHouseByTenantPhone) {
                log.info("更新房源ES中的租住人手机号,房间id:{}, 原手机号:{}, 新手机号:{}", roomel.getId(), mobile, newMobile);
                roomel.setTenantinfo(roomel.getTenantinfo().replaceAll(mobile, newMobile));
                IndexRequest indexRequest = new IndexRequest(ApiConstants.ROOMELENTIRY).id(roomel.getId().toString())
                        .source(JsonUtils.toJsonString(roomel), XContentType.JSON);
                request.add(indexRequest);
            }
            restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("更新房源ES中的租住人手机号异常", e);
            throw new RuntimeException(e);
        }
        log.info("更新房源ES中的租住人手机号, 原手机号:{}, 新手机号:{}, 更新完成", mobile, newMobile);
        return CommonResult.success(Boolean.TRUE);
    }
}
